﻿using System;
using System.Windows.Forms;
using System.Drawing;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IsreversI.GUI
{
    /// <summary>
    /// Represent a single tile on the board.
    /// 
    /// Displays what is currently on the tile and handles clicks.  This could
    /// have been derived from a PictureBox, but we were getting some freakish
    /// errors and decided that this would work just as well. (Which it does).
    /// </summary>
    class BoardTileControl : UserControl
    {
        #region membervars
        #region GUI elements
        #endregion

        private Visualisation.BoardVisualView visual;
        private GameLogic.GameStateController stateController;

        private ISet<PaintEventHandler> items;
        private Point PositionOnBoard;
        private Image currentImage;
        #endregion

        #region events
        #endregion

        #region properties
        public int X
        {
            get
            {
                return PositionOnBoard.X;
            }
        }

        public int Y
        {
            get
            {
                return PositionOnBoard.Y;
            }
        }
        #endregion

        #region constructors
        public BoardTileControl(Visualisation.BoardVisualView visual, GameLogic.GameStateController stateController, Point position)
        {
            this.PositionOnBoard = position;
            this.visual = visual;
            this.stateController = stateController;
            this.InitializeComponents();
        }

        private void InitializeComponents()
        {
            this.items = new HashSet<PaintEventHandler>();
            this.Paint += this.handlePaint;
            this.Click += this.handleClick;
            this.AutoSize = false;
            this.MinimumSize = new Size(15, 15);
            this.BorderStyle = BorderStyle.FixedSingle;
            this.Resize += this.handleResize;
            this.visual.TileObjectAdded[this.X, this.Y] += this.handleTileObjectAdded;
            this.visual.TileObjectRemoved[this.X, this.Y] += this.handleTileObjectRemoved;
            this.visual.AllObjectsRemoved += this.handleAllObjectsRemoved;
            this.DemandUpdate();
        }
        #endregion

        #region event handlers
        private void handlePaint(object sender, PaintEventArgs pea)
        {
            pea.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            pea.Graphics.DrawImage(this.currentImage, new Point(0, 0));
        }

        private void handleClick(object sender, EventArgs ea)
        {
            this.stateController.PlayMove(this.PositionOnBoard);
        }

        private void handleTileObjectAdded(object sender, Visualisation.VisualEventArgs vea)
        {
            if (this.PositionOnBoard != vea.Point)
                return;
            foreach (PaintEventHandler pea in vea.DrawCode)
                this.items.Add(pea);
            this.redrawImage();
        }

        private void handleTileObjectRemoved(object sender, Visualisation.VisualEventArgs vea)
        {
            if (this.PositionOnBoard != vea.Point)
                return;
            foreach (PaintEventHandler pea in vea.DrawCode)
                this.items.Remove(pea);
            this.redrawImage();
        }

        private void handleAllObjectsRemoved(object sender, Visualisation.VisualEventArgs vea)
        {
            this.items.Clear();
            this.redrawImage();
        }

        private void handleResize(object sender, EventArgs ea)
        {
            this.redrawImage();
        }
        #endregion

        #region public methods
        #endregion

        #region private methods
        void DemandUpdate()
        {
            this.items = this.visual.GetEffectsOnTile(this.PositionOnBoard);
            this.redrawImage();
        }

        void redrawImage()
        {
            Image newImage = new Bitmap(this.Size.Width, this.Size.Height);
            PaintEventArgs pea = new PaintEventArgs(Graphics.FromImage(newImage), this.ClientRectangle);
            foreach (PaintEventHandler peh in this.items)
                peh(this, pea);
            this.currentImage = newImage;
            this.Invalidate();
        }
        #endregion
    }
}
